/*
 * Copyright (C) 2009 Rafael Fernandes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.phonebooksharing.android.activities.maps;

import java.util.ArrayList;
import java.util.List;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Point;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Contacts.Photos;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;
import com.phonebooksharing.android.R;
import com.phonebooksharing.android.activities.contacts.ContactBrowserActivity;
import com.phonebooksharing.android.util.CloseableUtil;
import com.phonebooksharing.android.util.ContactUtils;
import com.phonebooksharing.android.util.GalleryUtilities;
import com.phonebooksharing.android.util.Global;
import com.phonebooksharing.android.util.NetworkHandlerTask;
import com.phonebooksharing.android.widgets.drawable.FastBitmapDrawable;
import com.phonebooksharing.dto.friend.ContactItem;

@SuppressWarnings("unchecked")
public class MapWhereAreTheyActivity extends MapActivity {
    
    private MapView mapView;
    private Gallery gallery;
    private View loading;
    private ContactAdapter adapter;
    private MapController mapController;
    private List<Overlay> mapOverlays;
    private ContactOverlay contactOverlay;
    private FastBitmapDrawable pin;
    private ContactItem focusContact;
    private int accuracy;
    
    public static final String ACCURACY = "a";
    
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.map_where_are_they);
        
        gallery = (Gallery) findViewById(R.id.gallery);
        // Set a item click listener, and just Toast the clicked position
        gallery.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView parent, View v, int position, long id) {
                adapter.navigateTo(position);
            }
        });
        
        final Intent i = getIntent();
        accuracy = i.getIntExtra(ACCURACY, 0);
        
        loading = findViewById(R.id.loading);
        adapter = new ContactAdapter(this);
        gallery.setAdapter(adapter);
        
        registerForContextMenu(gallery);

        initMap();
        
        new LoadContacts().execute();
    }
    
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        if(focusContact == null) {
            Toast.makeText(this, "There isn't a contact in focus!\nPlease select one to see its details", Toast.LENGTH_LONG);
        } else {
            menu.add(focusContact.name + "'s Details");
        }
    }
    
    @Override
    public boolean onContextItemSelected(MenuItem item) {
        Intent i = new Intent(MapWhereAreTheyActivity.this, ContactBrowserActivity.class);
        i.putExtra(ContactBrowserActivity.FRIEND_ITEM, focusContact);
        startActivity(i);
        return true;
    }
    
    private void initMap() {
        mapView = (MapView) findViewById(R.id.mapview);
        mapView.setBuiltInZoomControls(true);
        mapController = mapView.getController();

        final MyLocationOverlay myOverlay = new MyLocationOverlay(this, mapView);
        //FIXME: uncomment-me
//        myOverlay.enableCompass();
//        myOverlay.enableMyLocation();
        myOverlay.runOnFirstFix(new Runnable() {
            public void run() {
                mapController.animateTo(myOverlay.getMyLocation());
            }
        });
        
        mapController.setZoom(13);
        
        mapOverlays = mapView.getOverlays();
        mapOverlays.add(myOverlay);
        
        pin = new FastBitmapDrawable(BitmapFactory.decodeResource(getResources(), R.drawable.pin));
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(0, 0, 0, "Map Mode").setIcon(android.R.drawable.ic_menu_mapmode);
        return super.onCreateOptionsMenu(menu);
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case 0: {//refresh
                showDialog(MAP_MODE_DIALOG);
                return true;
            }
        }
        return false;
    }
    private static final int MAP_MODE_DIALOG = 0;

    @Override
    protected Dialog onCreateDialog(int id) {
        return new AlertDialog.Builder(this)
            .setTitle("Map Mode")
            .setItems(R.array.map_mode, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    switch (which) {
                    case 0:
                        mapView.setStreetView(true);
                        break;
                    case 1:
                        mapView.setSatellite(true);
                        break;
                    case 2:
                        mapView.setTraffic(true);
                        break;
                    default:
                        break;
                    }
                }
            })
            .create();
    }
    
    class LoadContacts extends NetworkHandlerTask<Void, ArrayList<ContactItem>, Void> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected Void doInBackground(Void... params) {
            
            try {
                final String url = String.format(Global.CONTACT_SERVLET_URL, "cl" /*ac*/, "" /*p*/, ""/*ps*/, ""/*c*/, accuracy /*a*/);
                ArrayList<ContactItem> list = (ArrayList<ContactItem>)doNetworkPost(url, Global.authItem);
                
                publishProgress(list);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(ArrayList<ContactItem>... values) {
            super.onProgressUpdate(values);
            
            adapter.list = values[0];
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
            
            loading.setVisibility(View.GONE);
            
            gallery.setVisibility(View.VISIBLE);
            gallery.requestFocus();

            adapter.notifyDataSetChanged();
        }
    }

    class ContactAdapter extends BaseAdapter {
        public ArrayList<ContactItem> list = new ArrayList<ContactItem>();
        private Context cx;
        private LayoutInflater li;
        
        public ContactAdapter(Context cx) {
            this.cx = cx;
            this.li = LayoutInflater.from(cx);
        }

        public void navigateTo(int position) {
            final ContactItem ci = list.get(position);
            
            GeoPoint gp = new GeoPoint((int)(ci.latitude * 1E6), (int)(ci.longitude * 1E6));
            mapOverlays.remove(contactOverlay);
            contactOverlay = new ContactOverlay(gp);
            mapOverlays.add(contactOverlay);

            focusContact = ci;
            mapController.animateTo(gp);
        }

        public int getCount() { 
            return list.size();
        }

        public Object getItem(int position) {
            return position;
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if (convertView == null) {
                convertView = li.inflate(R.layout.map_contact_gallery_item, null);
                
                holder = new ViewHolder();
                holder.icon = (ImageView) convertView.findViewById(android.R.id.icon);
                holder.border = convertView.findViewById(android.R.id.background);
                holder.name = (TextView) convertView.findViewById(android.R.id.text1);
                
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            
            final ContactItem cache = list.get(position);
            ContactUtils.setContactBorder(cache, holder.border);
            holder.name.setText(cache.name);
            
            final FastBitmapDrawable icon = GalleryUtilities.getFromContactCache(cache.andID);
            if (icon != null) {
                holder.icon.setImageBitmap(icon.getBitmap());
            } else {
                holder.icon.setImageBitmap(GalleryUtilities.noPictureBitmap.getBitmap());
                setImage(holder.icon, cache.andID);
            }
            return convertView;
        }
        
        void setImage(ImageView icon, long id) {//can't be new thread so we loose focus
            final Uri photoUri = Uri.parse("content://contacts/people/" + id + "/photo");
            Cursor c = cx.getContentResolver().query(photoUri, new String[] { Photos.DATA }, null, null, null);
            final byte[] data;
            try {
                if (c != null && c.moveToNext()) {
                    data = c.getBlob(0);
                } else {
                    //TODO: placeholder? already exists!!!
                    data = null;
                }
            } finally {
                CloseableUtil.safeClose(c);
                c = null;
            }
            
            if(data != null) {
                Bitmap b = BitmapFactory.decodeByteArray(data, 0, data.length);
                final Bitmap bm = GalleryUtilities.scaleBitmap(b, 55, 55);
                
                if(bm != null) {
                    GalleryUtilities.addToContactCache(id, bm);
                    icon.setImageBitmap(bm);
                }

                b.recycle();
                b = null;
            }
        }
    }

    static class ViewHolder {
        ImageView icon;
        View border;
        TextView name;
    }
    
    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }
    
    class ContactOverlay extends Overlay {
        GeoPoint p;
        public ContactOverlay(GeoPoint p) {
            this.p = p;
        }
        
        @Override
        public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
            super.draw(canvas, mapView, shadow);                   
 
            //---translate the GeoPoint to screen pixels---
            Point screenPts = new Point();
            mapView.getProjection().toPixels(p, screenPts);
 
            //---add the marker---
            canvas.drawBitmap(pin.getBitmap(), screenPts.x, screenPts.y - 50, null);         
            return true;
        }
    } 
}
